package com.kf.config.shiro;

import com.kf.config.filter.CsrfFilter;
import com.kf.pojo.Permission;
import com.kf.service.Impl.PermissionServiceImpl;
import org.apache.shiro.authc.AbstractAuthenticator;
import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;

import java.util.*;

/**
 * shiro配置
 *
 * @author Honey
 * @date 2022/12/17
 */
@Configuration
public class ShiroConfig {

    @Resource
    PermissionServiceImpl permissionServiceImpl;

    @Bean(name="userRealm")
    public UserRealm userRealm(){
        return new UserRealm();
    }

    @Bean(name="phoneCodeRealm")
    public PhoneCodeRealm phoneCodeRealm(){
        return new PhoneCodeRealm();
    }



    /**
     * shiro过滤器工厂bean
     *
     * @param securityManager 安全管理器
     * @return {@link ShiroFilterFactoryBean}
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager")DefaultWebSecurityManager securityManager){

        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);



        System.out.println("我是shiro权限控制过滤器");
        //没有权限默认跳转的页面
        shiroFilterFactoryBean.setUnauthorizedUrl("/noauth");
        //身份认证失败跳转到login页面
        shiroFilterFactoryBean.setLoginUrl("/tologin");
        //为权限赋予意义，即该权限能做什么事
        shiroFilterFactoryBean.setFilterChainDefinitionMap(setFilterChainDefinitionMap());

        return shiroFilterFactoryBean;

    }


    /**
     * 默认web安全管理器
     *
     * @param userRealm             用户领域
     * @param phoneCodeRealm        电话号码领域
     * @param abstractAuthenticator 抽象身份
     * @return {@link DefaultWebSecurityManager}
     */
    @Bean
    public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm,
                                                               @Qualifier("phoneCodeRealm") PhoneCodeRealm phoneCodeRealm,
                                                               @Qualifier("abstractAuthenticator") AbstractAuthenticator abstractAuthenticator){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        List<Realm> realms = new ArrayList<>();
        realms.add(userRealm);
        realms.add(phoneCodeRealm);
        securityManager.setRealms(realms);
        securityManager.setAuthenticator(abstractAuthenticator);

        return securityManager;

    }


    /**
     * 开启shiro 注解支持. 使以下注解能够生效 :
     * 需要认证 {@link org.apache.shiro.authz.annotation.RequiresAuthentication RequiresAuthentication}
     * 需要用户 {@link org.apache.shiro.authz.annotation.RequiresUser RequiresUser}
     * 需要访客 {@link org.apache.shiro.authz.annotation.RequiresGuest RequiresGuest}
     * 需要角色 {@link org.apache.shiro.authz.annotation.RequiresRoles RequiresRoles}
     * 需要权限 {@link org.apache.shiro.authz.annotation.RequiresPermissions RequiresPermissions}
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
    @Bean
    @Qualifier("abstractAuthenticator")
    public AbstractAuthenticator abstractAuthenticator(@Qualifier("userRealm") UserRealm userRealm,@Qualifier("phoneCodeRealm") PhoneCodeRealm phoneCodeRealm){
        // 自定义模块化认证器，用于解决多realm抛出异常问题
        //开始没用自定义异常问题，发现不管是账号密码错误还是什么错误
        //shiro只会抛出一个AuthenticationException异常
        ModularRealmAuthenticator authenticator = new MyCustomModularRealmAuthenticator();
        // 认证策略：AtLeastOneSuccessfulStrategy(默认)，AllSuccessfulStrategy，FirstSuccessfulStrategy
        authenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
        // 加入realms
        List<Realm> realms = new ArrayList<>();
        realms.add(userRealm);
        realms.add(phoneCodeRealm);
        authenticator.setRealms(realms);
        return authenticator;
    }

    /**
     * 系统自带的Realm管理，主要针对多realm
     */
    @Bean
    public ModularRealmAuthenticator modularRealmAuthenticator() {
        //自己重写的ModularRealmAuthenticator
        MyCustomModularRealmAuthenticator modularRealmAuthenticator = new MyCustomModularRealmAuthenticator();
        modularRealmAuthenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
        return modularRealmAuthenticator;
    }



    /**
     * 配置 拦截过滤器链.  map的键 : 资源地址 ;  map的值 : 所有默认Shiro过滤器实例名
     * 默认Shiro过滤器实例 参考 : {@link org.apache.shiro.web.filter.mgt.DefaultFilter}
     *
     */
    private Map<String, String> setFilterChainDefinitionMap() {
        Map<String, String> filterMap = new LinkedHashMap<>();
        //注册 数据库中所有的权限 及其对应url
        //数据库中查询所有权限
        List<Permission> allPermission = permissionServiceImpl.findAll();
        for (Permission p : allPermission) {
            if(p.getPath()!=null&& !"".equals(p.getPath())){
//                System.out.println(p.getPerms());
                //拦截器中注册所有的权限
                filterMap.put(p.getPath(), "perms[" +p.getPerms() + "]");
            }
        }

        filterMap.put("/login","anon");
        //公开访问的资源
        filterMap.put("/static/**", "anon");
        //公开接口地址
        filterMap.put("/open/api/**", "anon");
        //配置登出页,shiro已经帮我们实现了跳转
        filterMap.put("/logout", "logout");
        //所有资源都需要经过验证
//        filterMap.put("/**", "authc");
        return filterMap;
    }

    //配置文件中配置允许的Referer

    @Value("${csrf.domains}")
    private List<String> accessReferer;

    @Bean
    public FilterRegistrationBean csrfFilter() {
        System.out.println("我是crsf过滤器");
        FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
        // 这里使用的是配置文件信息，获取配置文件中的csrf.domains相关值信息
        if (accessReferer != null && accessReferer.size() > 0) {
            filterRegistration.setFilter(new CsrfFilter(accessReferer));
        } else {
            filterRegistration.setFilter(new CsrfFilter(Collections.emptyList()));
        }
        filterRegistration.setEnabled(true);
        filterRegistration.addUrlPatterns("/*");
        return filterRegistration;
    }





}
